package com.sc.nft.service.impl;

import java.util.Date;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.WeightRandom;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.sc.nft.dao.DaoIdentityDao;
import com.sc.nft.dao.PrizeDrawActivityAwardDao;
import com.sc.nft.dao.PrizeDrawActivityDao;
import com.sc.nft.dao.UserCollectionDao;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.PrizeDrawDTO;
import com.sc.nft.entity.dto.RaffleRouletteDTO;
import com.sc.nft.entity.vo.NumberOfDrawsVO;
import com.sc.nft.entity.vo.PrizeDrawVO;
import com.sc.nft.entity.vo.RaffleRouletteVO;
import com.sc.nft.entity.vo.TrochalDiskVO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.EquityPropsService;
import com.sc.nft.service.PrizeDrawActivityAwardService;
import com.sc.nft.service.UserAssetsService;
import com.sc.nft.service.UserEquityPropsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 抽奖活动的奖品(PrizeDrawActivityAward)表服务实现类
 *
 * @author wwc
 * @since 2023-08-22 14:07:07
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class PrizeDrawActivityAwardServiceImpl implements PrizeDrawActivityAwardService {

    private final PrizeDrawActivityAwardDao prizeDrawActivityAwardDao;

    private final PrizeDrawActivityDao prizeDrawActivityDao;

    private final UserEquityPropsService userEquityPropsService;
    private final EquityPropsService equityPropsService;
    private final UserAssetsService userAssetsService;
    private final DaoIdentityDao daoIdentityDao;
    private final UserCollectionDao userCollectionDao;

    @Override
    public RaffleRouletteVO raffleRoulette(RaffleRouletteDTO raffleRouletteDTO, UserInfo userInfo) {
        RaffleRouletteVO raffleRouletteVO = new RaffleRouletteVO();

        PrizeDrawActivity prizeDrawActivity = prizeDrawActivityDao.getById(raffleRouletteDTO.getId());
        if (BeanUtil.isEmpty(prizeDrawActivity)) {
            throw new GlobalRunTimeException("活动不存在");
        }
        // 当前时间大于开始时间，小于结束时间，活动状态为1
        if (System.currentTimeMillis() > prizeDrawActivity.getStartTime().getTime() && System.currentTimeMillis() < prizeDrawActivity.getEndTime().getTime()) {
            raffleRouletteVO.setActivityStatus(1);
        }
        // 当前时间大于结束时间，活动状态为2
        if (System.currentTimeMillis() > prizeDrawActivity.getEndTime().getTime()) {
            raffleRouletteVO.setActivityStatus(2);
        }
        // 当前时间小于开始时间，活动状态为0
        if (System.currentTimeMillis() < prizeDrawActivity.getStartTime().getTime()) {
            raffleRouletteVO.setActivityStatus(0);
        }
        // 根据活动的绑定的权益id查询用户的权益数量
        Integer havingCountByUserId = userEquityPropsService.getHavingCountByUserId(prizeDrawActivity.getPropId(), userInfo.getId());
        // 根据活动id查询轮盘
        List<PrizeDrawActivityAward> byPrizeDrawActivityId = prizeDrawActivityAwardDao.getByPrizeDrawActivityId(prizeDrawActivity.getId());

        List<TrochalDiskVO> trochalDiskVOS = BeanUtil.copyToList(prizeDrawActivityAwardDao.raffleRoulette(raffleRouletteDTO), TrochalDiskVO.class);
        if (prizeDrawActivity.getStatus().equals(2)) {
            raffleRouletteVO.setActivityStatus(2);
            raffleRouletteVO.setPrizeDrawCount(havingCountByUserId);
            raffleRouletteVO.setList(trochalDiskVOS);
            return raffleRouletteVO;
        }
        // 用Java8表达式特性 获取所有的奖品剩余数量,如果没有了,活动结束
        Integer residualRewardQuantity = byPrizeDrawActivityId.stream().mapToInt(PrizeDrawActivityAward::getResidue).sum();
        if (residualRewardQuantity <= 0) {
            raffleRouletteVO.setActivityStatus(2);
            raffleRouletteVO.setPrizeDrawCount(havingCountByUserId);
            raffleRouletteVO.setList(trochalDiskVOS);
            return raffleRouletteVO;
        }
        // 用户抽奖券数量
        raffleRouletteVO.setPrizeDrawCount(havingCountByUserId);
        raffleRouletteVO.setList(trochalDiskVOS);
        return raffleRouletteVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PrizeDrawVO prizeDraw(PrizeDrawDTO prizeDrawDTO, UserInfo user) {
        PrizeDrawVO prizeDrawVO = new PrizeDrawVO();
        /*
        1.根据活动id查询活动信息
        2.查看活动是否开始了
        3.查看用户是否有对应的权益道具(抽奖券)
        4.获取当前活动id的轮盘,根据每一个剩余的数量计算概率
        5.记录日志
        6.获得奖品,让后发放奖励 记录日志,发放到用户的背包中,记录日志
         */

        PrizeDrawActivity prizeDrawActivity = prizeDrawActivityDao.getById(prizeDrawDTO.getId());
        if (BeanUtil.isEmpty(prizeDrawActivity)) {
            throw new GlobalRunTimeException("活动不存在");
        }

        List<DaoIdentity> daoIdentities = daoIdentityDao.getByDaoId(prizeDrawActivity.getDaoId());

        if(CollUtil.isEmpty(daoIdentities)){
            throw new GlobalRunTimeException("您尚未加入该DAO");
        }

        List<Long> collectionIds = daoIdentities.stream().map(DaoIdentity::getCollectionId).collect(Collectors.toList());
        boolean has = userCollectionDao.userHasCollections(user.getId(), collectionIds);
        if(!has){
            throw new GlobalRunTimeException("您尚未加入该DAO");
        }

        // 当前时间大于开始时间，小于结束时间，活动状态为1
        if (System.currentTimeMillis() > prizeDrawActivity.getStartTime().getTime() && System.currentTimeMillis() < prizeDrawActivity.getEndTime().getTime()) {
            if (prizeDrawActivity.getAuditStatus().equals(1)) {
                if (prizeDrawActivity.getStatus().equals(1)) {
                    // 根据活动的绑定的权益id查询用户的权益数量
                    Integer havingCountByUserId = userEquityPropsService.getHavingCountByUserId(prizeDrawActivity.getPropId(), user.getId());
                    if (havingCountByUserId < 1) {
                        throw new GlobalRunTimeException("抽奖券不足");
                    }
                    // 根据活动id查询轮盘
                    List<PrizeDrawActivityAward> byPrizeDrawActivityId = prizeDrawActivityAwardDao.getByPrizeDrawActivityId(prizeDrawDTO.getId());
                    // 用Java8表达式特性 获取所有的奖品剩余数量
                    Integer residualRewardQuantity = byPrizeDrawActivityId.stream().mapToInt(PrizeDrawActivityAward::getResidue).sum();
                    if (residualRewardQuantity <= 0) {
                        throw new GlobalRunTimeException("活动已结束");
                    }
                    // 根据轮盘的剩余数量计算概率.
                    List<WeightRandom.WeightObj<Long>> weightList = new ArrayList<WeightRandom.WeightObj<Long>>();
                    for (PrizeDrawActivityAward prizeDrawActivityAward : byPrizeDrawActivityId) {
                        if (prizeDrawActivityAward.getResidue() > 0) {
                            weightList.add(new WeightRandom.WeightObj(prizeDrawActivityAward.getId(), Convert.toDouble(Convert.toBigDecimal(prizeDrawActivityAward.getResidue()).divide(Convert.toBigDecimal(residualRewardQuantity), 8, BigDecimal.ROUND_CEILING))));
                        }
                    }
                    WeightRandom wr = RandomUtil.weightRandom(weightList);
                    // 奖品id
                    Long prizeId = (Long) wr.next();
                    // 把奖品的剩余数量减一
                    prizeDrawActivityAwardDao.updateResidue(prizeId);
                    // 扣除掉用户的抽奖券
                    userEquityPropsService.subVoucher(prizeDrawActivity.getPropId(), EquityPropsTypeEnum.RAFFLE_TICKET, user.getId(), 1, "抽奖券消耗", prizeDrawActivity.getId());
                    // 奖励
                    PrizeDrawActivityAward prizeDrawActivityAward = prizeDrawActivityAwardDao.getById(prizeId);
                    // 记录日志
                    PrizeDrawActivityAwardLog prizeDrawActivityAwardLog = new PrizeDrawActivityAwardLog();
                    prizeDrawActivityAwardLog.setPrizeDrawActivityId(prizeDrawDTO.getId());
                    prizeDrawActivityAwardLog.setAwardType(prizeDrawActivityAward.getType());
                    prizeDrawActivityAwardLog.setRecordName(prizeDrawActivity.getNameActivity());
                    prizeDrawActivityAwardLog.setRemark("");
                    prizeDrawActivityAwardLog.setDaoId(prizeDrawActivity.getDaoId());
                    prizeDrawActivityAwardLog.setUserUuid(user.getUserUuid());
                    prizeDrawActivityAwardLog.setUserTel(user.getUserTel());
                    prizeDrawActivityAwardLog.setNickName(user.getNickName());
                    prizeDrawActivityAwardLog.setActivityName(prizeDrawActivity.getNameActivity());
                    prizeDrawActivityAwardLog.setPropId(prizeDrawActivity.getPropId());
                    prizeDrawActivityAwardLog.setPropName(prizeDrawActivity.getPropName());
                    prizeDrawActivityAwardLog.setPropExpend(1);
                    prizeDrawActivityAwardLog.setResidueProop(havingCountByUserId - 1);
                    prizeDrawActivityAwardLog.setAwardId(prizeDrawActivityAward.getId());
                    prizeDrawActivityAwardLog.setAwardName(prizeDrawActivityAward.getAwardName());
                    prizeDrawActivityAwardLog.setAwardSum(prizeDrawActivityAward.getNumber());
                    prizeDrawActivityAwardLog.setResidueAwardSum(prizeDrawActivityAward.getResidue() - 1);
                    prizeDrawActivityAwardLog.setSort(prizeDrawActivityAward.getSort());
                    prizeDrawActivityAwardLog.insert();
                    // 发放奖励,2为道具,1为星球碎片
                    if (prizeDrawActivityAward.getType().equals(2)) {
                        EquityProps equityProps = equityPropsService.getById(prizeDrawActivityAward.getAwardId());
                        userEquityPropsService.addEquityPropsByUser(equityProps, user.getId(), UserEquityPropsGetTypeEnum.PRIZE_DRAW, prizeDrawActivityAward.getNumber(), prizeDrawActivity.getNameActivity(), prizeDrawActivity.getId(),BigDecimal.ZERO,UserEquityPropsGetTypeEnum.PRIZE_DRAW,prizeDrawActivity.getId());
                    } else if (prizeDrawActivityAward.getType().equals(1)) {
                        //   发放星球碎片
                        userAssetsService.addIntegralByUserId(Convert.toBigDecimal(prizeDrawActivityAward.getNumber()), user.getId(), CoinCategoryEnum.INTEGRAL, AssetChangeLogEnum.LOTTERY, prizeDrawActivityAward.getPrizeDrawActivityId(), prizeDrawActivityAward.getAwardName());
                    }
                    prizeDrawVO.setAwardName(prizeDrawActivityAward.getAwardName());
                    prizeDrawVO.setImg(prizeDrawActivityAward.getImg());
                    prizeDrawVO.setId(prizeDrawActivityAward.getId());
                    prizeDrawVO.setQuantity(prizeDrawActivityAward.getNumber());
                    return prizeDrawVO;
                } else {
                    throw new GlobalRunTimeException("活动已结束");
                }
            } else {
                throw new GlobalRunTimeException("活动未审核");
            }
        } else if (System.currentTimeMillis() > prizeDrawActivity.getEndTime().getTime()) {
            throw new GlobalRunTimeException("活动已结束");
        } else {
            throw new GlobalRunTimeException("活动未开始");
        }
    }

    @Override
    public NumberOfDrawsVO numberOfDraws(RaffleRouletteDTO raffleRouletteDTO, UserInfo user) {
        PrizeDrawActivity prizeDrawActivity = prizeDrawActivityDao.getById(raffleRouletteDTO.getId());
        if (BeanUtil.isEmpty(prizeDrawActivity)) {
            throw new GlobalRunTimeException("活动不存在");
        }
        Integer havingCountByUserId = userEquityPropsService.getHavingCountByUserId(prizeDrawActivity.getPropId(), user.getId());
        NumberOfDrawsVO numberOfDrawsVO = new NumberOfDrawsVO();
        numberOfDrawsVO.setPrizeDrawCount(havingCountByUserId);
        return numberOfDrawsVO;
    }

}
